﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.Tableaus.BannerTableau
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using System;
using TaleWorlds.Core;
using TaleWorlds.DotNet;
using TaleWorlds.Engine;
using TaleWorlds.Engine.Options;
using TaleWorlds.Library;

#nullable disable
namespace TaleWorlds.MountAndBlade.View.Tableaus
{
  public class BannerTableau
  {
    private bool _isFinalized;
    private bool _isEnabled;
    private bool _isNineGrid;
    private bool _isDirty;
    private Banner _banner;
    private int _latestWidth = -1;
    private int _latestHeight = -1;
    private int _tableauSizeX;
    private int _tableauSizeY;
    private float RenderScale = 1f;
    private float _customRenderScale = 1f;
    private Scene _scene;
    private Camera _defaultCamera;
    private Camera _nineGridCamera;
    private MetaMesh _currentMultiMesh;
    private GameEntity _currentMeshEntity;
    private int _meshIndexToUpdate;

    public Texture Texture { get; private set; }

    internal Camera CurrentCamera => !this._isNineGrid ? this._defaultCamera : this._nineGridCamera;

    private TableauView View
    {
      get
      {
        return (NativeObject) this.Texture != (NativeObject) null ? this.Texture.TableauView : (TableauView) null;
      }
    }

    public BannerTableau()
    {
      this.SetEnabled(true);
      this.FirstTimeInit();
    }

    public void OnTick(float dt)
    {
      if (!this._isEnabled || this._isFinalized)
        return;
      this.Refresh();
      this.View?.SetDoNotRenderThisFrame(false);
    }

    private void FirstTimeInit()
    {
      this._scene = Scene.CreateNewScene(enable_decals: false);
      this._scene.DisableStaticShadows(true);
      this._scene.SetName("BannerTableau.Scene");
      this._scene.SetDefaultLighting();
      this._defaultCamera = TableauCacheManager.CreateDefaultBannerCamera();
      this._nineGridCamera = TableauCacheManager.CreateNineGridBannerCamera();
      this._isDirty = true;
    }

    private void Refresh()
    {
      if (!this._isDirty)
        return;
      if ((NativeObject) this._currentMeshEntity != (NativeObject) null)
        this._scene.RemoveEntity(this._currentMeshEntity, 111);
      if (this._banner == null)
        return;
      MatrixFrame identity = MatrixFrame.Identity;
      this._currentMultiMesh = this._banner.ConvertToMultiMesh();
      this._currentMeshEntity = this._scene.AddItemEntity(ref identity, this._currentMultiMesh);
      this._currentMeshEntity.ManualInvalidate();
      this._currentMultiMesh.ManualInvalidate();
      this._isDirty = false;
    }

    private void SetEnabled(bool enabled)
    {
      this._isEnabled = enabled;
      this.View?.SetEnable(this._isEnabled);
    }

    public void SetTargetSize(int width, int height)
    {
      this._latestWidth = width;
      this._latestHeight = height;
      if (width <= 0 || height <= 0)
      {
        this._tableauSizeX = 10;
        this._tableauSizeY = 10;
      }
      else
      {
        this.RenderScale = NativeOptions.GetConfig(NativeOptions.NativeOptionsType.ResolutionScale) / 100f;
        this._tableauSizeX = (int) ((double) width * (double) this._customRenderScale * (double) this.RenderScale);
        this._tableauSizeY = (int) ((double) height * (double) this._customRenderScale * (double) this.RenderScale);
      }
      this.View?.SetEnable(false);
      this.View?.AddClearTask(true);
      this.Texture?.ReleaseNextFrame();
      this.Texture = TableauView.AddTableau(nameof (BannerTableau), new RenderTargetComponent.TextureUpdateEventHandler(this.BannerTableauContinuousRenderFunction), (object) this._scene, this._tableauSizeX, this._tableauSizeY);
      this.Texture.TableauView.SetSceneUsesContour(false);
    }

    public void SetBannerCode(string value)
    {
      this._banner = !string.IsNullOrEmpty(value) ? BannerCode.CreateFrom(value).CalculateBanner() : (Banner) null;
      this._isDirty = true;
    }

    public void OnFinalize()
    {
      if (!this._isFinalized)
      {
        this._scene?.ClearDecals();
        this._scene?.ClearAll();
        this._scene?.ManualInvalidate();
        this._scene = (Scene) null;
        this.View?.SetEnable(false);
        this.Texture?.ReleaseNextFrame();
        this.Texture = (Texture) null;
        this._defaultCamera?.ReleaseCamera();
        this._defaultCamera = (Camera) null;
        this._nineGridCamera?.ReleaseCamera();
        this._nineGridCamera = (Camera) null;
      }
      this._isFinalized = true;
    }

    public void SetCustomRenderScale(float value)
    {
      if (this._customRenderScale.ApproximatelyEqualsTo(value))
        return;
      this._customRenderScale = value;
      if (this._latestWidth == -1 || this._latestHeight == -1)
        return;
      this.SetTargetSize(this._latestWidth, this._latestHeight);
    }

    internal void BannerTableauContinuousRenderFunction(Texture sender, EventArgs e)
    {
      Scene userData = (Scene) sender.UserData;
      TableauView tableauView = sender.TableauView;
      if ((NativeObject) userData == (NativeObject) null)
      {
        tableauView.SetContinuousRendering(false);
        tableauView.SetDeleteAfterRendering(true);
      }
      else
      {
        userData.EnsurePostfxSystem();
        userData.SetDofMode(false);
        userData.SetMotionBlurMode(false);
        userData.SetBloom(false);
        userData.SetDynamicShadowmapCascadesRadiusMultiplier(0.31f);
        tableauView.SetRenderWithPostfx(false);
        tableauView.SetScene(userData);
        tableauView.SetCamera(this.CurrentCamera);
        tableauView.SetSceneUsesSkybox(false);
        tableauView.SetDeleteAfterRendering(false);
        tableauView.SetContinuousRendering(true);
        tableauView.SetDoNotRenderThisFrame(true);
        tableauView.SetClearColor(0U);
      }
    }

    public void SetIsNineGrid(bool value)
    {
      this._isNineGrid = value;
      this._isDirty = true;
    }

    public void SetMeshIndexToUpdate(int value) => this._meshIndexToUpdate = value;

    public void SetUpdatePositionValueManual(Vec2 value)
    {
      if (this._currentMultiMesh.MeshCount < 1 || this._meshIndexToUpdate < 0 || this._meshIndexToUpdate >= this._currentMultiMesh.MeshCount)
        return;
      Mesh meshAtIndex = this._currentMultiMesh.GetMeshAtIndex(this._meshIndexToUpdate);
      MatrixFrame localFrame = meshAtIndex.GetLocalFrame();
      localFrame.origin.x = 0.0f;
      localFrame.origin.y = 0.0f;
      localFrame.origin.x += value.X / 1528f;
      localFrame.origin.y -= value.Y / 1528f;
      meshAtIndex.SetLocalFrame(localFrame);
    }

    public void SetUpdateSizeValueManual(Vec2 value)
    {
      if (this._currentMultiMesh.MeshCount < 1 || this._meshIndexToUpdate < 0 || this._meshIndexToUpdate >= this._currentMultiMesh.MeshCount)
        return;
      Mesh meshAtIndex = this._currentMultiMesh.GetMeshAtIndex(this._meshIndexToUpdate);
      MatrixFrame localFrame = meshAtIndex.GetLocalFrame();
      float x = value.X / 1528f / meshAtIndex.GetBoundingBoxWidth();
      float y = value.Y / 1528f / meshAtIndex.GetBoundingBoxHeight();
      Vec3 eulerAngles = localFrame.rotation.GetEulerAngles();
      localFrame.rotation = Mat3.Identity;
      localFrame.rotation.ApplyEulerAngles(eulerAngles);
      localFrame.rotation.ApplyScaleLocal(new Vec3(x, y, 1f));
      meshAtIndex.SetLocalFrame(localFrame);
    }

    public void SetUpdateRotationValueManual((float, bool) value)
    {
      if (this._currentMultiMesh.MeshCount < 1 || this._meshIndexToUpdate < 0 || this._meshIndexToUpdate >= this._currentMultiMesh.MeshCount)
        return;
      Mesh meshAtIndex = this._currentMultiMesh.GetMeshAtIndex(this._meshIndexToUpdate);
      MatrixFrame localFrame = meshAtIndex.GetLocalFrame();
      float a = (float) ((double) value.Item1 * 2.0 * 3.1415927410125732);
      Vec3 scaleVector = localFrame.rotation.GetScaleVector();
      localFrame.rotation = Mat3.Identity;
      localFrame.rotation.RotateAboutUp(a);
      localFrame.rotation.ApplyScaleLocal(scaleVector);
      if (value.Item2)
        localFrame.rotation.RotateAboutForward(3.14159274f);
      meshAtIndex.SetLocalFrame(localFrame);
    }
  }
}
